package com.tsfyun.common.base.extension;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tsfyun.common.base.config.OrikaBeanMapper;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.SqlsCriteria;
import tk.mybatis.mapper.weekend.Fn;
import tk.mybatis.mapper.weekend.WeekendSqls;
import tk.mybatis.mapper.weekend.reflection.Reflections;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
public class ServiceImpl<T> implements IService<T> {

    private static final Logger logger = LoggerFactory.getLogger(ServiceImpl.class);

    @Autowired(required = false)
    private Mapper<T> mapper;

    @Autowired
    public OrikaBeanMapper beanMapper;

    // 缓存子类泛型类型
    private Class<T> cache = null;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(T t) {
        return this.retBool(mapper.insert(t));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeById(Serializable o) {
        return this.delBool(mapper.deleteByPrimaryKey(o));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean remove(T t) {
        return this.delBool(mapper.delete(t));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeByIds(List ids) {
        if(CollUtil.isEmpty(ids)) {
            log.warn("参数ids集合为空");
            return true;
        }
        return this.delBool(mapper.deleteByIdList(ids));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveNonNull(T t) {
        return this.retBool(mapper.insertSelective(t));
    }

    @Override
    public T getById(Serializable o) {
        return mapper.selectByPrimaryKey(o);
    }

    @Override
    public int count(T t) {
        return mapper.selectCount(t);
    }

    @Override
    public List<T> list(T t) {
        return mapper.select(t);
    }

    @Override
    public T getOne(T t) {
        return mapper.selectOne(t);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateById(T t) {
        return this.retBool(mapper.updateByPrimaryKey(t));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateByIdSelective(T t) {
        return this.retBool(mapper.updateByPrimaryKeySelective(t));
    }

    /**
     * 需手动赋值id/createBy/dateCreated/updateBy/dateUpdated
     *
     * @param list
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int savaBatch(List<T> list) {
        if(CollUtil.isEmpty(list)) {
            return 0;
        }
        return mapper.insertListUseAllCols(list);
    }

    @Override
    public PageInfo<T> pageList(T pojo, Integer pageNo, Integer pageSize, String orderBy) {
        PageHelper.startPage(pageNo, pageSize, orderBy);
        List<T> list = mapper.select(pojo);
        return new PageInfo<T>(list);
    }

    /**
     * 排序参数
     *
     * @param orderByColumn
     * @param sort
     * @return
     */
    @Override
    public String getOrderBy(String orderByColumn, String sort) {
        if (StringUtils.isEmpty(orderByColumn)) {
            return "";
        }
        if (StringUtils.isEmpty(sort)) sort = "desc";
        return orderByColumn + " " + sort;
    }

    @Override
    public PageInfo<T> pageList(Integer pageNo, Integer pageSize, SqlsCriteria where, List<OrderItem> sorts, Fn<T, Object>... fields) {
        Example.Builder builder;
        if (null == fields || fields.length == 0) {
            //查询所有
            builder = Example.builder(getTypeArgument());
        } else {
            //查询指定字段,where的内容拿出来进行动态sql拼接
            List<String> queryFieldsList = getFields(fields);
            String[] selectFields = new String[queryFieldsList.size()];
            queryFieldsList.toArray(selectFields);
            builder = Example.builder(getTypeArgument()).select(selectFields);
        }
        if (where != null) {
            builder = builder.where(where);
        }
        if (CollectionUtil.isNotEmpty(sorts)) {
            for (OrderItem orderItem : sorts) {
                if (!orderItem.isAsc()) {
                    builder.orderByDesc(orderItem.getColumn());
                } else {
                    builder.orderByAsc(orderItem.getColumn());
                }
            }
        }
        Example example = builder.build();
        if (Objects.nonNull(pageNo) && Objects.nonNull(pageSize)) {
            // 分页插件
            PageHelper.startPage(pageNo, pageSize);
        }
        List<T> list = this.mapper.selectByExample(example);
        return new PageInfo<T>(list);
    }

    @Override
    public List<String> getFields(Fn<T, Object>... fields) {
        if (null == fields || fields.length == 0) {
            //查询所有
            return null;
        } else {
            List<String> fieldsList = Arrays.asList(fields).stream().map(Reflections::fnToFieldName).collect(Collectors.toList());
            return fieldsList;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateDocumentStatus(T t,Serializable documentId,String oldDocumentStatus,@NonNull String nowDocumentStatus) {
        T updateEntity;
        try {
            updateEntity = (T) t.getClass().newInstance();
            ReflectUtil.setFieldValue(updateEntity,"statusId",nowDocumentStatus);
        } catch (InstantiationException e) {
            logger.info("获取单据{}，单据id:{}，状态异常",t.getClass().getName(),documentId);
            throw new ServiceException("获取单据状态异常");
        } catch (IllegalAccessException e) {
            logger.info("获取单据{}，单据id:{}，状态异常",t.getClass().getName(),documentId);
            throw new ServiceException("获取单据状态异常");
        }
        Example.Builder builder = Example.builder(getTypeArgument());
        builder.where(WeekendSqls.custom().andEqualTo("id",documentId).andEqualTo("statusId",oldDocumentStatus));
        int updateCnt = this.mapper.updateByExampleSelective(updateEntity,builder.build());
        return updateCnt;
    }

    /**
     * 获取子类泛型类型
     *
     * @return
     */
    public Class<T> getTypeArgument() {
        if (cache == null) {
            cache = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return cache;
    }


    protected boolean retBool(Integer result) {
        return SqlHelper.retBool(result);
    }

    public static boolean delBool(Integer result) {
        return null != result && result >= 0;
    }

}
